`include "common_def.v" 
`include "decode_def.v"
module MODULE_ID_EX	(
input  											clk_i,							
input  											rst_i,							
input												id_valid_i,
input												exe_ready_i,
input												last_write_pr_en_i,
output											write_pr_en_o,
output											DEp_ready_o,
output											exe_start_o,
input												stop_i,
input												intr_stop_i,
input												wash_i,
input												add_nouse_inst_i,
input												add_start_i,
output											pc_recover_o,
output											write_pr_en1_o,

input		[31:0]							inst_i,
input  	[`WIDTH-1:0]					pc_i,							
input  	[`WIDTH-1:0]					src1_i,					
input  	[`WIDTH-1:0]					src2_i,					
input  	[`WIDTH-1:0]					imm_i,						
input  	[`OP_NUM-1:0]				alu_key_i,				
input		[1:0]								mul_sign_key_i,
input  	[`A_NUM-1:0]				alu_A_key_i,			
input  	[`B_NUM-1:0]				alu_B_key_i,			
input  	[`SHAMT_NUM-1:0]		shamt_key_i,			
input  											alu_result_key_i,
input  	[`RESULT_NUM-1:0]		result_key_i,	
input  	[`CSR_KEY_NUM-1:0]	data_csr_key_i,	
input												csr_i_or_r_key_i,
input  	[`LOAD_NUM-1:0]		  load_data_key_i,	
input  	[7:0]								store_mask_i,			
input  											read_en_i,					
input  											write_en_i,				
input  											wenR_i,						
input  											wen_csr_i,					
input  											is_ecall_i,				
input  											is_mret_i,				
input  											is_load_i,					
input  	[4:0]								addr_dst_i,				
input  	[11:0]							addr_csr_i,				
input		[3:0]								inst_key_i,
input		[`R_ADDR_W-1:0]			  addr_src1_r_i,
input		[`R_ADDR_W-1:0]				addr_src2_r_i,
input												is_fencei_i,
input		[2:0]								ls_size_i,

output	[31:0]							inst_o,
output 	[`WIDTH-1:0]					pc_o,							
output 	[`WIDTH-1:0]					src1_o,					
output 	[`WIDTH-1:0]					src2_o,					
output 	[`WIDTH-1:0]					imm_o,						
output 	[`OP_NUM-1:0]				alu_key_o,				
output	[1:0]								mul_sign_key_o,
output 	[`A_NUM-1:0]				alu_A_key_o,			
output 	[`B_NUM-1:0]				alu_B_key_o,			
output 	[`SHAMT_NUM-1:0]		shamt_key_o,			
output 											alu_result_key_o,	
output 	[`RESULT_NUM-1:0]		result_key_o,		
output 	[`CSR_KEY_NUM-1:0]	data_csr_key_o,	
output											csr_i_or_r_key_o,
output 	[`LOAD_NUM-1:0]		  load_data_key_o,
output 	[7:0]								store_mask_o,			
output 											read_en_o,					
output 											write_en_o,				
output 											wenR_o,						
output 											wen_csr_o,					
output 											is_ecall_o,				
output 											is_mret_o,				
output 											is_load_o,					
output 	[4:0]								addr_dst_o,				
output 	[11:0]							addr_csr_o,				
output		[3:0]								inst_key_o,
output		[`R_ADDR_W-1:0]			  addr_src1_r_o,
output		[`R_ADDR_W-1:0]				addr_src2_r_o,
output												is_fencei_o,
output		[2:0]								ls_size_o
);

//当add_nouse_inst时，主要是在此处处理，要使寄存器的值不真正修改，但是于指令相
//关的关键寄存器要输出无效值构建空指令。
//保持不向前级输出ready，确保不会有新的指令被取入。
//write_regs_en
assign write_pr_en1_o = write_regs_en;
wire write_regs_en;
wire id_valid_r;
Reg #(1,0) id_valid_reg(clk_i,rst_i,exe_ready_i?0:id_valid_i,id_valid_r,id_valid_i|exe_ready_i);
assign write_regs_en =(id_valid_i|id_valid_r) & exe_ready_i&(~stop_i)&(~add_nouse_inst_i);
//catch a new inst
wire catch_new_inst;
Reg #(1,0) catch_new_inst_r(clk_i,rst_i,wash_i ? 1'b0:write_regs_en&intr_stop_i,catch_new_inst,wash_i|(write_regs_en&intr_stop_i));
//exe_start_o
wire exe_start_normal;
Reg #(1,0) exe_start_normal_reg(clk_i,rst_i,write_regs_en,exe_start_normal,1);
assign exe_start_o = (exe_start_normal | add_start_i)&(~catch_new_inst);
//DEp_ready_o 
wire DEp_ready;
wire DEp_ready_r;
assign DEp_ready = (id_valid_i|id_valid_r) & exe_ready_i;
Reg #(1,1) DEp_ready_o_reg(clk_i,rst_i, last_write_pr_en_i? 1'b0:DEp_ready,DEp_ready_r,DEp_ready|last_write_pr_en_i);
assign DEp_ready_o = (DEp_ready | DEp_ready_r);

assign write_pr_en_o = write_regs_en&(~intr_stop_i);
//pc_recover
assign pc_recover_o =(id_valid_i|id_valid_r) & exe_ready_i&(~stop_i)&(add_nouse_inst_i);

wire  											read_en_r;					
wire  											write_en_r;				
wire  											wenR_r;						
wire  											wen_csr_r;					
wire  											is_ecall_r;				
wire  											is_mret_r;				

assign read_en_o = add_nouse_inst_i ?0:read_en_r;					
assign write_en_o = add_nouse_inst_i ?0:write_en_r;				
assign wenR_o = add_nouse_inst_i ?0:wenR_r;						
assign wen_csr_o = add_nouse_inst_i ?0:(wen_csr_r &(~catch_new_inst));	//当正在执行写CSR寄存器指令时发生中断，要保证这条指令不执行，需要将wen_csr_o拉低，但是中断发生时又需要写mstate寄存器，这个使能信号在CSRS中是或上中断发生标志信号的，不会收到wen_csr_o的影响，wen_csr_o只影响指令写CSRS，不会影响中断或异常引起的写CSRS				
assign is_ecall_o = add_nouse_inst_i ?0:is_ecall_r;				
assign is_mret_o = add_nouse_inst_i ?0:is_mret_r;				
Reg#(32,0) reg_inst_o(clk_i,rst_i,wash_i?0:inst_i,inst_o,write_regs_en|wash_i);
Reg#(`WIDTH,`RST_PC) reg_pc_o(clk_i,rst_i,wash_i?0:pc_i,pc_o,write_regs_en|wash_i);
Reg#(`WIDTH,0) reg_src1_o(clk_i,rst_i,wash_i?0:src1_i,src1_o,write_regs_en|wash_i);
Reg#(`WIDTH,0) reg_src2_o(clk_i,rst_i,wash_i?0:src2_i,src2_o,write_regs_en|wash_i);
Reg#(`WIDTH,0) reg_imm_o(clk_i,rst_i,wash_i?0:imm_i,imm_o,write_regs_en|wash_i);
Reg#(`OP_NUM,0) reg_alu_key_o(clk_i,rst_i,wash_i?0:alu_key_i,alu_key_o,write_regs_en|wash_i);
Reg#(2,0) reg_mul_sign_key_o(clk_i,rst_i,wash_i?0:mul_sign_key_i,mul_sign_key_o,write_regs_en|wash_i);
Reg#(`A_NUM,0) reg_alu_A_key_o(clk_i,rst_i,wash_i?0:alu_A_key_i,alu_A_key_o,write_regs_en|wash_i);
Reg#(`B_NUM,0) reg_alu_B_key_o(clk_i,rst_i,wash_i?0:alu_B_key_i,alu_B_key_o,write_regs_en|wash_i);
Reg#(`SHAMT_NUM,0) reg_shamt_key_o(clk_i,rst_i,wash_i?0:shamt_key_i,shamt_key_o,write_regs_en|wash_i);
Reg#(1,0) reg_alu_result_key_o(clk_i,rst_i,wash_i?0:alu_result_key_i,alu_result_key_o,write_regs_en|wash_i);
Reg#(`RESULT_NUM,0) reg_result_key_o(clk_i,rst_i,wash_i?0:result_key_i,result_key_o,write_regs_en|wash_i);
Reg#(`CSR_KEY_NUM,0) reg_data_csr_key_o(clk_i,rst_i,wash_i?0:data_csr_key_i,data_csr_key_o,write_regs_en|wash_i);
Reg#(1,0) reg_csr_i_or_r_key_o(clk_i,rst_i,wash_i?0:csr_i_or_r_key_i,csr_i_or_r_key_o,write_regs_en|wash_i);
Reg#(`LOAD_NUM,0) reg_load_data_key_o(clk_i,rst_i,wash_i?0:load_data_key_i,load_data_key_o,write_regs_en|wash_i);
Reg#(8,0) reg_store_mask_o(clk_i,rst_i,wash_i?0:store_mask_i,store_mask_o,write_regs_en|wash_i);
Reg#(1,0) reg_read_en_o(clk_i,rst_i,wash_i?0:read_en_i,read_en_r,write_regs_en|wash_i);
Reg#(1,0) reg_write_en_o(clk_i,rst_i,wash_i?0:write_en_i,write_en_r,write_regs_en|wash_i);
Reg#(1,0) reg_wenR_o(clk_i,rst_i,wash_i?0:wenR_i,wenR_r,write_regs_en|wash_i);
Reg#(1,0) reg_wen_csr_o(clk_i,rst_i,wash_i?0:wen_csr_i,wen_csr_r,write_regs_en|wash_i);
Reg#(1,0) reg_is_ecall_o(clk_i,rst_i,wash_i?0:is_ecall_i,is_ecall_r,write_regs_en|wash_i);
Reg#(1,0) reg_is_mret_o(clk_i,rst_i,wash_i?0:is_mret_i,is_mret_r,write_regs_en|wash_i);
Reg#(1,0) reg_is_load_o(clk_i,rst_i,wash_i?0:is_load_i,is_load_o,write_regs_en|wash_i);
Reg#(5,0) reg_addr_dst_o(clk_i,rst_i,wash_i?0:addr_dst_i,addr_dst_o,write_regs_en|wash_i);
Reg#(12,0) reg_addr_csr_o(clk_i,rst_i,wash_i?0:addr_csr_i,addr_csr_o,write_regs_en|wash_i);
Reg#(4,0) reg_inst_key_o(clk_i,rst_i,wash_i?0:inst_key_i,inst_key_o,write_regs_en|wash_i);
Reg#(`R_ADDR_W,0) reg_addr_src1_r_o(clk_i,rst_i,wash_i?0:addr_src1_r_i,addr_src1_r_o,write_regs_en|wash_i);
Reg#(`R_ADDR_W,0) reg_addr_src2_r_o(clk_i,rst_i,wash_i?0:addr_src2_r_i,addr_src2_r_o,write_regs_en|wash_i);
Reg#(1,0) reg_is_fencei_o(clk_i,rst_i,wash_i?0:is_fencei_i,is_fencei_o,write_regs_en|wash_i);
Reg#(3,0) reg_ls_size_o(clk_i,rst_i,wash_i?0:ls_size_i,ls_size_o,write_regs_en|wash_i);
endmodule
